package com.hog.utils;

/**
 * 分布式ID获取工具类
 *
 * @author 唐晴
 * @date 2020年08月05日
 * @since JDK 1.8
 */
public class IdUtil {
    private static IdWorker a = null;
    private static IdWorker b = null;

    static {
        a = new IdWorker(1L, 5L);
        b = new IdWorker(1L, 6L);
    }

    private IdUtil() {

    }

    public static Long generateDistributedId() {
        Long var0 = a.nextId();
        return var0;
    }


    /**
     * @Author: dengshengwu
     * @DateTime: 2019/3/29 17:15
     * @Version: 2.0.0
     * @description: 分布式ID生成器
     **/
    private static class IdWorker {
        private long workerId;
        private long datacenterId;
        private long sequence = 0L;
        private long twepoch = 1493801340486L;
        private long datacenterIdBits = 1L;
        private long workerIdBits = 3L;
        private long maxWorkerId;
        private long maxDatacenterId;
        private long sequenceBits;
        private long workerIdShift;
        private long datacenterIdShift;
        private long timestampLeftShift;
        private long sequenceMask;
        private long lastTimestamp;

        public IdWorker(long var1, long var3) {
            this.maxWorkerId = ~(-1L << (int) this.workerIdBits);
            this.maxDatacenterId = ~(-1L << (int) this.datacenterIdBits);
            this.sequenceBits = 7L;
            this.workerIdShift = this.sequenceBits;
            this.datacenterIdShift = this.sequenceBits + this.workerIdBits;
            this.timestampLeftShift = this.sequenceBits + this.workerIdBits + this.datacenterIdBits;
            this.sequenceMask = ~(-1L << (int) this.sequenceBits);
            this.lastTimestamp = -1L;
            if (var1 <= this.maxDatacenterId && var1 >= 0L) {
                if (var3 <= this.maxWorkerId && var3 >= 0L) {
                    this.workerId = var3;
                    this.datacenterId = var1;
                    System.out.println(String.format("IdWorker timestamp left shift %d, datacenter id bits %d, worker id bits %d, sequence bits %d, workerid %d, datacenterId %d", this.timestampLeftShift, this.datacenterIdBits, this.workerIdBits, this.sequenceBits, var3, var1));
                } else {
                    throw new IllegalArgumentException(String.format("worker Id can't be greater than %d or less than 0", this.maxWorkerId));
                }
            } else {
                throw new IllegalArgumentException(String.format("datacenter Id can't be greater than %d or less than 0", this.maxDatacenterId));
            }
        }

        public synchronized long nextId() {
            long var1 = this.timeGen();
            if (var1 < this.lastTimestamp) {
                System.out.println(String.format("clock is moving backwards.  Rejecting requests until %d.", this.lastTimestamp));
                throw new RuntimeException(String.format("Clock moved backwards.  Refusing to generate id for %d milliseconds", this.lastTimestamp - var1));
            } else {
                if (this.lastTimestamp == var1) {
                    this.sequence = this.sequence + 1L & this.sequenceMask;
                    if (this.sequence == 0L) {
                        var1 = this.tilNextMillis(this.lastTimestamp);
                    }
                } else {
                    this.sequence = 0L;
                }

                this.lastTimestamp = var1;
                return var1 - this.twepoch << (int) this.timestampLeftShift | this.datacenterId << (int) this.datacenterIdShift | this.workerId << (int) this.workerIdShift | this.sequence;
            }
        }

        protected long tilNextMillis(long var1) {
            long var3;
            for (var3 = this.timeGen(); var3 <= var1; var3 = this.timeGen()) {
                ;
            }

            return var3;
        }

        protected long timeGen() {
            return System.currentTimeMillis();
        }
    }
}